함수형 인터페이스
서론
우테코에서 글렌이 기본형 함수형 인터페이스에 대해 소개해줬다. 그런데 함수형 인터페이스가 뭐지..?
한번 알아보도록 하자.
함수형 인터페이스
함수형 인터페이스란?
하나의 추상 메소드를 지정하는 인터페이스다 모던 자바 인 액션 中
쉽게말해 추상메소드가 하나인 인터페이스를 의미한다.
@FunctionalInterface
public interface GameAction {
void execute(final List<String> commands);
}
Java에서는 @FunctionalInterface 라는 어노테이션을 통해 해당 인터페이스가 함수형 인터페이스임을 명시할 수도 있다.
이는 인터페이스가 함수형 인터페이스 형식을 따르지 않으면 컴파일 단계에서 오류를 발생시킨다.
함수형 인터페이스 왜 쓰는데?
함수형 인터페이스를 이해하기에 앞서 람다식을 이해할 필요가 있다.
람다식?
람다식이란 메서드로 전달할 수 있는 익명함수를 간략하게 표현한 것을 의미한다.
간결한 방식으로 코드를 전달할 수 있다는 장점이 있다.
어떻게 사용하길래 간결한 방식이 되는걸까?
람다식의 사용
// 파라티터 화살표 바디
(o1, o2) -> o2 - o1;
람다 표현식은 파라미터, 화살표, 바로 이루어진다.
그래서 어떻게 쓰는건데?
자바에서는 기본 함수형 인터페이스를 몇가지 제공해준다. 만들어 쓸 수도 있지만 일단은 제공하고있는 기본 함수형 인터페이스에 대해 간략하게 알아가보자.
Function<T, R>UnaryOperator<T>Consumer<T>Predicate<T>Supplier<T>
Funciton<T, R>
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
...
}
T 타입 인자를 받고 R타입 객체를 리턴한다. 라고 읽을 수 있다.
apply() 메소드를 통해 사용할 수 있다.
예를 들어 다음과 같이 사용할 수 있다.
@Test
public void 함수를_반환_값으로_활용하는_예제() {
Function<String, Integer> toInt = value -> Integer.parseInt(value);
final Integer number = toInt.apply("100");
//toInt(100);
assertThat(number).isEqualTo(100);
}
위 메소드는 String 값을 받아서 Integer.parseInt 메소드를 통해 Integer로 반환해주는 함수형 인터페이스 toInt에 대한 내용이다.
UnaryOperator<T>
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
T 타입 인자를 받고 T타입 객체를 리턴한다. 라고 읽을 수 있다.
identity() 메소드로 사용할 수 있다.
위에서 설명한 Function<T, R>인터페이스와 동일하나 입력값과 반환값이 동일한 타입이다. 정도로 이해하면 될 것 같다.
예를 들어 다음과 같이 사용할 수 있다.
UnaryOperator<String> appendEndLine = value -> value + System.lineSeparator();
System.out.print(appendEndLine.apply("hello"));
System.out.print(appendEndLine.apply("world"));
위 메소드는 String 값을 받아서 개행(System.lineSeparator())를 끝에 추가한 String을 반환하는 함수형 인터페이스 appendEndLine에 대한 내용이다.
Consumer<T>
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
...
}
T 타입 인자를 받아 사용한다. 라고 읽을 수 있다.
accept() 메소드를 통해 사용할 수 있다.
예를 들어 다음과 같이 사용할 수 있다.
final Consumer<String> print = input -> System.out.println(input);
print.accept("HelloWorld!");
위 메소드는 String 값을 받아서 출력하는 함수형 인터페이스 print에 대한 내용이다.
Predicate<T>
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
...
}
T 타입의 객체를 인자로 받아 boolean 결과를 반환한다. 라고 읽을 수 있다.
test() 메소드를 통해 사용할 수 있다.
예를 들어 다음과 같이 사용할 수 있다.
final Predicate<Integer> isPositive = number -> number > 0;
isPositive.test(3) // true
isPositive.test(-3) // false
위 메소드는 Integer 값을 받아서 해당 숫자가 양수인지 boolean으로 반환하는 함수형 인터페이스 isPositive에 대한 내용이다.
Supplier<T>
@FunctionalInterface
public interface Supplier<T> {
T get();
}
T 타입의 값을 반환한다. 라고 읽을 수 있다.
get() 메소드를 통해 값을 반환받는다.
예를 들어 다음과 같이 사용할 수 있다.
Supplier<String> givenString = () -> "StringValue";
단순히 값을 반환하는 함수형 인터페이스다. 왜 사용할까? 의구심이 드는 인터페이스다.
Lazy Evaluation이라는 키워드를 얻을 수 있다. 자세한 내용은 이곳에서 다루지는 않겠다.
결론
함수형 인터페이스를 보고 어떻게 동작하는지 말로 설명할 수 있게 되었다.
어떤 로직을 봤을 때 아! 함수형 인터페이스로 표현할 수 있겠구나! 라는 생각이 들 수 있을 정도로 익숙해지는 시간을 가져보는것이 중요할 것 같다.